package com.biboheart.adapter.compiler.lexical;

import com.biboheart.adapter.compiler.enums.CharType;
import com.biboheart.adapter.compiler.enums.TokenState;
import com.biboheart.adapter.compiler.enums.TokenType;
import com.biboheart.adapter.compiler.token.Token;
import com.biboheart.adapter.compiler.utils.TokenUtils;
import com.biboheart.adapter.support.enums.InstructEnum;
import com.biboheart.adapter.support.utils.ObjectTypeUtils;

final class TokenizerKeyword implements Tokenizer {
    private TokenBuffer tokenBuffer;
    private TokenState state;

    @Override
    public TokenState entry(char ch, int offset, String content) {
        CharType charType = TokenUtils.getCharType(ch);
        if (!CharType.CHAR_LETTER.equals(charType)) {
            state = TokenState.STATE_FAIL;
            return TokenState.STATE_FAIL;
        }
        tokenBuffer = new TokenBuffer(offset);
        tokenBuffer.push(ch);
        state = TokenState.STATE_CONTINUE;
        char next = TokenUtils.getNext(content, offset);
        charType = TokenUtils.getCharType(next);
        if (CharType.CHAR_EOF.equals(charType) || CharType.CHAR_SPACE.equals(charType) || CharType.CHAR_CHARACTER.equals(charType)) {
            state = InstructEnum.contains(tokenBuffer.buffer()) ? TokenState.STATE_END : TokenState.STATE_FAIL;
        }
        return state;
    }

    @Override
    public TokenState getState() {
        return state;
    }

    @Override
    public TokenState analyse(char ch, int offset, String content) {
        if (TokenState.STATE_END.equals(state)) {
            return TokenState.STATE_END_BACK;
        }
        if (!TokenState.STATE_CONTINUE.equals(state)) {
            return state;
        }
        CharType charType = TokenUtils.getCharType(ch);
        if (!CharType.CHAR_LETTER.equals(charType)) {
            state = TokenState.STATE_FAIL;
            return state;
        }
        tokenBuffer.push(ch);
        char next = TokenUtils.getNext(content, offset);
        charType = TokenUtils.getCharType(next);
        if (CharType.CHAR_EOF.equals(charType) || CharType.CHAR_SPACE.equals(charType) || CharType.CHAR_CHARACTER.equals(charType)) {
            state = InstructEnum.contains(tokenBuffer.buffer()) ? TokenState.STATE_END : TokenState.STATE_FAIL;
        }
        return state;
    }

    @Override
    public Token generateToken() {
        if (!TokenState.STATE_END.equals(state) && !TokenState.STATE_END_BACK.equals(state)) {
            return null;
        }
        String value = ObjectTypeUtils.convertType(tokenBuffer.value(TokenType.TOKEN_KEYWORD), String.class);
        return new Token(tokenBuffer.getStart(),
                tokenBuffer.getEnd(),
                TokenType.TOKEN_KEYWORD,
                value,
                value,
                tokenBuffer.buffer());
    }
}
